没想到蒟蒻我有生之年竟然也能A上一道VK CUP的题。
传送门
原题链接:
数据范围与时有所不同。
下文中的B数组就是棒子的长度。
题解
首先考虑没有开凿操作时,如何判断当前的情况是否合法。
不难发现,能否将一根棒子放进一个洞穴里,取决于该洞穴到根中高度最小的节点,设每个节点到根节点路径上高度最小值为$Min[i]$(可以$O(n)$构造出来)。对$Min$和$B$两个数组分别从小到大排序。
当满足$B[i] \leq Min[j]$时,棒子$i$就可以放进洞穴$j$里。设第$i$根棒子可以放进$num[i]$个洞穴。当满足$\forall i,num[i]\geq i$时,就合法。也就是当且仅当$\min_{i=1}^{n}{(num[i]-i)}\geq 0$时合法。
然后考虑开凿操作。由于不知道开凿哪一个节点,那么$O(n)$枚举过去。然后二分要开凿的高度。
比如要对图中这个节点进行开凿,那么它的子树中的以该节点为最小值的节点的$Min$值就会改变,所以$Min$数组中就可能需要删去几个原先的值然后加入几个新元素(可能加入二分后的高度或原先到根节点链上的次小值),由于$Min$数组中的每一个元素都对$num$数组中一个连续区间产生贡献,且删除一个元素后一整个区间的值被减1,加入一个元素后一整个区间的值被加1,所以就套个线段树维护全局最小值即可。并且由于每个节点到树根的链上只有一个最小值,所以对于每一个节点,只有一个节点在二分的时候会影响到它,所以时间复杂度为$O(n\log n \log B_i)$。
然后蒟蒻我傻呵呵地卡了半天常数,死活过不去,只好想$O(n\log n)$的做法。
经过ZZK大佬的点拨,我发现其实根本不需要二分。
找到最长的$num_i-B_i$的值小于零的棒子,那么如果有解,就一定要将某个洞穴的高度开凿到这根棒子的长度。
于是乎就可以$O(n)$枚举开凿哪一个洞穴,然后检查一下开凿完之后是否合法就好了。
代码
下面是两个log的代码(贼慢):
1 |
|
一个log的代码(跑的飞快):
1 |
|